/*******************************************************************************
 * Copyright (c) 2008-2009 zhang yuexiang.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */ 
package org.xfeep.asura.bootstrap.test;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.List;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.PropertyException;

import org.junit.Test;
import org.xfeep.asura.bootstrap.ComponentDefinitionInfo;
import org.xfeep.asura.bootstrap.CompositeDefinitionInfo;
import org.xfeep.asura.core.ComponentDefinition;
import org.xfeep.asura.core.InjectPropertyItem;
import org.xfeep.asura.core.ReferenceDefinition;
import org.xfeep.asura.core.match.SmartMatcher;
import org.xfeep.asura.core.reflect.TypeItem;
import org.xfeep.asura.core.test.eager.EagerComponentTestSet;
import org.xfeep.asura.core.test.factory.FactoryComponentTestSet;
import org.xfeep.asura.core.test.lazy.LazyComponentTestSet;
import org.xfeep.asura.core.test.ondemand.OnDemandComponentTestSet;

import static junit.framework.Assert.*;


public class AsuraXmlComponentLoaderTestSet {

	
	public void assertArrayEquals(Object a, Object o){
		if (a != null){
			assertEquals(Array.getLength(a), Array.getLength(o));
			for (int i = 0; i < Array.getLength(a); i++){
				Object ai = Array.get(a, i);
				Object oi = Array.get(o, i);
				if (ai.getClass().isArray()){
					assertArrayEquals(ai, oi);
				}else{
					assertEquals(ai, oi);
				}
			}
		}else{
			assertNull(o);
		}
	}
	
	public void checkComponentDefinitionEquality(ComponentDefinition c, ComponentDefinition o){
		
		assertEquals(c.getName(), o.getName());
		assertEquals(c.getType(), o.getType());
		assertEquals(c.getScope(), o.getScope());
		
		assertArrayEquals(c.getInterfaces(), o.getInterfaces());
		
		assertEquals(c.getImplement(), o.getImplement());
		assertEquals(c.getInit(), o.getInit());
		assertEquals(c.getActivate(), o.getActivate());
		assertEquals(c.getDeactivate(), o.getDeactivate());
		assertEquals(c.getDestroy(), o.getDestroy());
		assertEquals(c.getActivate(), o.getActivate());
		
		assertArrayEquals(c.getIndexKeys(), o.getIndexKeys());
		
		assertArrayEquals(c.getConstPropertySet(), o.getConstPropertySet());
		
		checkReferenceArrayEquality(c.getReferences(), o.getReferences());
		
		
		
		
		assertEquals(c.getDynamicReferencePosition(), o.getDynamicReferencePosition());
		
	}

	public void checkReferenceArrayEquality(ReferenceDefinition[] r,
			ReferenceDefinition[] o) {
		if (r != null){
			if (r.length != o.length){
				System.out.println("fail for debug");
			}
			assertEquals(r.length, o.length);
			for (int i = 0; i < r.length; i++){
				ReferenceDefinition ri = r[i];
				ReferenceDefinition oi = o[i];
				checkReferenceEquality(ri, oi);
				
			}
		}else{
			assertNull(o);
		}
	}

	public void checkReferenceEquality(ReferenceDefinition ri,
			ReferenceDefinition oi) {
		assertEquals(ri.getName(), oi.getName());
		assertEquals(ri.getServiceClass(), oi.getServiceClass());
		assertEquals(ri.getMultiplicityType(), oi.getMultiplicityType());
		assertEquals(ri.getContractType(), oi.getContractType());
		assertEquals(  ( (SmartMatcher)ri.getMatcher() ).getMatcherExpression() ,   ( (SmartMatcher)oi.getMatcher() ).getMatcherExpression());
		checkBindEquality(ri.getBind(), oi.getBind());
		assertEquals(ri.getOrder(), oi.getOrder());
		checkInjectPropertyItemArrayEquality(ri.getInjectProperties(), oi.getInjectProperties());
	}

	public void checkInjectPropertyItemArrayEquality(
			InjectPropertyItem[] t,
			InjectPropertyItem[] o) {
		if (t != null){
			if (t.length != o.length){
				System.out.println("fail for debug");
			}
			assertEquals(t.length, o.length);
			for (int  i = 0; i < t.length; i++){
				InjectPropertyItem ti = t[i];
				InjectPropertyItem oi = o[i];
				assertEquals(ti.getType(), oi.getType());
				assertEquals(ti.getName(), oi.getName());
				assertEquals(ti.getValueExpression(), oi.getValueExpression());
			}
		}else{
			assertNull(o);
		}
	}

	public void checkBindEquality(TypeItem b, TypeItem o) {
		if (b != null){
			assertEquals(b.getType(), o.getType());
			assertEquals(b.getName(), o.getName());
		}else{
			assertNull(o);
		}
	}
	
	@Test
	public void testAllEagerComponentInCoreTestSet() throws JAXBException {
		Class<?>[] eccs = EagerComponentTestSet.class.getDeclaredClasses();
		
		String compositeName = "eager-composite";
		
		checkComposite(eccs, compositeName);
		
	}

	@Test
	public void testAllLazyComponentInCoreTestSet() throws JAXBException {
		Class<?>[] eccs = LazyComponentTestSet.class.getDeclaredClasses();
		
		String compositeName = "lazy-composite";
		
		checkComposite(eccs, compositeName);
		
	}
	
	
	@Test
	public void testAllFactoryComponentInCoreTestSet() throws JAXBException {
		Class<?>[] eccs = FactoryComponentTestSet.class.getDeclaredClasses();
		
		String compositeName = "factory-composite";
		
		checkComposite(eccs, compositeName);
		
	}
	
	@Test
	public void testAllOnDemandComponentInCoreTestSet() throws JAXBException {
		Class<?>[] eccs = OnDemandComponentTestSet.class.getDeclaredClasses();
		
		String compositeName = "on-demand-composite";
		
		checkComposite(eccs, compositeName);
		
	}

	
	public void checkComposite(Class<?>[] eccs, String compositeName)
			throws JAXBException, PropertyException {
		List<ComponentDefinition> cds = new ArrayList<ComponentDefinition>();
		CompositeDefinitionInfo cod = new CompositeDefinitionInfo(compositeName);
		
		JAXBContext jaxbContext = JAXBContext.newInstance(CompositeDefinitionInfo.class);
		for (Class<?> ecc : eccs){
			ComponentDefinition cd = ComponentDefinition.create(ecc);
			if (cd != null){
//				if (!ecc.getName().endsWith("WriteServiceFacotryWithDynamicRef")){
//					continue;
//				}
				cds.add(cd);
				cod.components.add(ComponentDefinitionInfo.convert(cd));
			}
		}
	
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		Marshaller marshaller = jaxbContext.createMarshaller();
		marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
		marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
		marshaller.marshal(cod, out);
		byte[] outArray = out.toByteArray();
		try {
			String displayStr = new String(outArray, "UTF-8");
			System.out.println(displayStr);
		} catch (UnsupportedEncodingException e1) {
			e1.printStackTrace();
		}
		ByteArrayInputStream in = new ByteArrayInputStream(outArray);
		
		CompositeDefinitionInfo ucod = (CompositeDefinitionInfo)jaxbContext.createUnmarshaller().unmarshal(in);
		
		assertEquals(cod.name, ucod.name);
		assertEquals(cod.components.size(), ucod.components.size());
		for (int i = 0; i < cds.size(); i++) {
			ComponentDefinitionInfo cdi = ucod.components.get(i);
			try {
				System.out.println("begin check " + cdi.implement);
				ComponentDefinition cd = cdi.createComponentDefinitionIngoreAnnotation(Thread.currentThread().getContextClassLoader());
				checkComponentDefinitionEquality(cds.get(i), cd);
			} catch (ClassNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	
}
